#include "CanRoute.h"
#include "zdbc.h"
#include <QDebug>

std::unique_ptr<CanRoute> CanRoute::canRouteInstance = nullptr;

std::unique_ptr<CanRoute>& CanRoute::getInstance()
{
    static std::once_flag flag;
    std::call_once(flag, []() {
        canRouteInstance = std::make_unique<CanRoute>();
        canRouteInstance->init();
    });
    return canRouteInstance;
}

CanRoute::CanRoute()
    : itsDbcPaser(), itsCan()
    , itsSendThread(std::bind(&CanRoute::sendLoop, this)), isRunning(false), itsMutex(), itsRecvMutex(), itsCond(), itsRecvData()
{
    memset(itsRecvData, 0, sizeof(ZCAN_Receive_Data) * ICan::MAX_RECV_SIZE);
}

CanRoute::~CanRoute()
{
    stop();
}

void CanRoute::init()
{
    itsCan.reigsterListenerCb(std::bind(&CanRoute::updateRecvData, this, std::placeholders::_1));
    itsSendPool.emplace(0xE1, nullptr);
    itsSendPool.emplace(0x107, nullptr);
    itsSendPool.emplace(0x120, nullptr);
    itsSendPool.emplace(0x12A, nullptr);
    itsSendPool.emplace(0x132, nullptr);
    itsSendPool.emplace(0x140, nullptr);
    itsSendPool.emplace(0x141, nullptr);
    itsSendPool.emplace(0x155, nullptr);
    itsSendPool.emplace(0x17D, nullptr);
    itsSendPool.emplace(0x1D3, nullptr);
    itsSendPool.emplace(0x1E1, nullptr);
    itsSendPool.emplace(0x1E5, nullptr);
    itsSendPool.emplace(0x1E9, nullptr);
    itsSendPool.emplace(0x1F2, nullptr);
    itsSendPool.emplace(0x230, nullptr);
    itsSendPool.emplace(0x32A, nullptr);
    itsSendPool.emplace(0x32B, nullptr);
    itsSendPool.emplace(0x32C, nullptr);
    itsSendPool.emplace(0x32D, nullptr);
    itsSendPool.emplace(0x32E, nullptr);
    itsSendPool.emplace(0x32F, nullptr);
    itsSendPool.emplace(0x332, nullptr);
    itsSendPool.emplace(0x339, nullptr);
    itsSendPool.emplace(0x33A, nullptr);
    itsSendPool.emplace(0x33C, nullptr);
    itsSendPool.emplace(0x359, nullptr);
    itsSendPool.emplace(0x35C, nullptr);
    itsSendPool.emplace(0x35D, nullptr);
    itsSendPool.emplace(0x35E, nullptr);
    itsSendPool.emplace(0x363, nullptr);
    itsSendPool.emplace(0x36A, nullptr);
    itsSendPool.emplace(0x36D, nullptr);
    itsSendPool.emplace(0x36E, nullptr);
    itsSendPool.emplace(0x370, nullptr);
    itsSendPool.emplace(0x371, nullptr);
    itsSendPool.emplace(0x372, nullptr);
    itsSendPool.emplace(0x373, nullptr);
    itsSendPool.emplace(0x374, nullptr);
    itsSendPool.emplace(0x390, nullptr);
    itsSendPool.emplace(0x394, nullptr);
    itsSendPool.emplace(0x395, nullptr);
    itsSendPool.emplace(0x41D, nullptr);
    itsSendPool.emplace(0x449, nullptr);
    itsSendPool.emplace(0x471, nullptr);
    itsSendPool.emplace(0x4C5, nullptr);
    itsSendPool.emplace(0x4C7, nullptr);
    itsSendPool.emplace(0x532, nullptr);
    itsSendPool.emplace(0x53A, nullptr);
    itsSendPool.emplace(0x53B, nullptr);
    itsSendPool.emplace(0x53D, nullptr);
    itsSendPool.emplace(0x565, nullptr);
    itsSendPool.emplace(0x600, nullptr);
    itsSendPool.emplace(0x602, nullptr);
    itsSendPool.emplace(0x604, nullptr);
    itsSendPool.emplace(0x605, nullptr);
    itsSendPool.emplace(0x614, nullptr);
    itsSendPool.emplace(0x615, nullptr);
    itsSendPool.emplace(0x62A, nullptr);
    itsSendPool.emplace(0x635, nullptr);
    itsSendPool.emplace(0x651, nullptr);
    itsSendPool.emplace(0x652, nullptr);
    itsSendPool.emplace(0x653, nullptr);
    itsSendPool.emplace(0x654, nullptr);
    itsSendPool.emplace(0x686, nullptr);

}

bool CanRoute::start()
{
    bool ret = false;
    do
    {
        itsCan.configCanDevice(zlg::UsbCan::USBCAN_FD_200U, 0, 0,
                               zlg::BaudrateDef::Baudrate_1000000,
                               zlg::UsbCanAbitDef::UsbCanAbit_500kbps,
                               zlg::UsbCanDbitDef::UsbCanDbit_2Mbps , true);

        if(itsCan.OpenCan() == OperationResult::Success)
        {
            qDebug() << "can open Success\n";
        }
        else
        {
            itsCan.CloseCan();
            ret = false;
            break;
        }

        if(itsDbcPaser.load(DBC_PATH))
        {
            itsDbcPaser.printMessages();
        }
        else
        {
            ret = false;
            break;
        }

        itsDbcPaser.foreachDbcMessageMap([this](DBCMessage* msg){
            do{
                auto sIt = itsSendPool.find(msg->nID);
                if(sIt != itsSendPool.end())
                {
                    itsSendPool[msg->nID] = msg;
                    break;
                }

                auto rIt = itsSendPool.find(msg->nID);
                if(rIt != itsSendPool.end())
                {
                    itsSendPool[msg->nID] = msg;
                    break;
                }

                qDebug() << "unknown msg : " << msg->strName;
            }while(false);

        });

        isRunning.store(true);
        std::lock_guard<std::mutex> lock(itsMutex);
        itsCond.notify_one();

        ret = true;
    } while(false);

    return ret;
}

void CanRoute::stop()
{
    itsCan.CloseCan();
    isRunning = false;

    {
        // 注意解锁！！！！！！！
        std::lock_guard<std::mutex> lock(itsMutex);
        itsCond.notify_one();
    }

    if(itsSendThread.joinable())
    {
        itsSendThread.join();
    }
}

void CanRoute::sendSignal(const uint16_t& msgId, const std::string& sigName, double value)
{
    if(isRunning.load())
    {
        bool ret = itsDbcPaser.updateDbcMsg(msgId, sigName, value);
        if(!ret)
        {
            qDebug() << "Messag: " << msgId << " sig:" << sigName << "not find";
        }
    }
    else
    {
        qDebug() << "Can device not started!!!";
    }
}

bool CanRoute::isRouteRunning() const
{
    return isRunning.load();
}

void CanRoute::sendLoop()
{
    {
        if(!isRunning)
        {
            std::unique_lock<std::mutex> lock(itsMutex);
            itsCond.wait(lock);
        }
    }
    qDebug() << "SendLoop Running!\n";
    uint64_t count = 0;
    while(isRunning.load())
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(20));
        for(auto& v : itsSendPool)
        {
            if(v.second)
            {
                std::vector<uint8_t> out;

                if(itsDbcPaser.encodeAsCanMessage(v.second, out))
                {
                    auto ret = itsCan.SendCanMsg(v.second->nID, SendType::StandardFrame, out);
                    if(ret == OperationResult::DeviceIsNotOpen)
                    {
                        std::cout << "Send fail" << std::endl;
                    }
                }
                else
                {
                    // std::cout << "Decode fail : " << std::hex << v.second->nID << std::dec << std::endl;
                }
            }
        }
        count++;
    }
    qDebug() << "SendLoop Exit!\n";
}


void CanRoute::updateRecvData(ZCAN_Receive_Data* input)
{
    std::lock_guard<std::mutex> lock(itsRecvMutex);
    memcpy(itsRecvData, input, sizeof(ZCAN_Receive_Data) * ICan::MAX_RECV_SIZE);
}

bool CanRoute::getSigPhysicsData(const uint32_t& canId, const std::string& signalName, double& out)
{
    ZCAN_Receive_Data* msg = nullptr;
    bool ret = false;
    for(int i = 0; i < ICan::MAX_RECV_SIZE; i++)
    {
        if(itsRecvData[i].frame.can_id == canId)
        {
            msg = &itsRecvData[i];
            break;
        }
    }
    if(msg)
    {
        auto dbcMsgIt = itsSendPool.find(msg->frame.can_id);
        if(dbcMsgIt != itsSendPool.end())
        {
            itsDbcPaser.encodeCanMsg(dbcMsgIt->second, (void*)&msg->frame);
            DBCSignal* sig = itsDbcPaser.findSignalWithMessage(*dbcMsgIt->second, signalName);
            out = ZDBC_CalcActualValue(sig, &sig->nRawValue);
            ret = true;
        }
    }
    else
    {
        // qDebug() << "msg : " << canId << " not find";
    }
    return ret;
}

int CanRoute::getMsgIdBySigName(const char* sigName)
{
    return itsDbcPaser.getMsgIdBySigName(sigName);
}


